library(httr)
library(rjson)
library(OpenStreetMap)
## Warning: package 'OpenStreetMap' was built under R version 4.0.3
library(leaflet)
## Warning: package 'leaflet' was built under R version 4.0.3
library(scales)
library(dplyr)
library(purrr)
library(tidyverse)
library(sf)
library(htmltools)
library(htmlwidgets)
library(googlePolylines)
## Warning: package 'googlePolylines' was built under R version 4.0.3
library (rStrava) # devtools::install_github('fawda123/rStrava')
This was the tutorial I followed to get the Strava API set up. I followed steps one and two, then switched to this tutorial. Then in R, create the authentication token using your personal information from your API. Replace the app_name, app_client_id, and app_secret objects with the relevant info from your account.
app_name <- 'myappname' # chosen by user
app_client_id <- 'myid' # an integer, assigned by Strava
app_secret <- 'xxxxxxxx' # an alphanumeric secret, assigned by Strava
# create the authentication token
stoken <- httr::config(token = strava_oauth(app_name, app_client_id, app_secret, app_scope="activity:read_all"))
Using the Strava API, I pulled all activities since June 1, 2019. This includes runs, bike rides, hikes, yoga, etc. This process relies on the rStrava package, which I navigated with the help of its developers at this link and this link
# get activities list
my_runs <- get_activity_list(stoken, id = NULL, before = NULL, after = as.Date("2019-06-01"), club = FALSE)
I filtered all of my activities to show only runs. I also created a new dataframe with a subset of columns to make the data easier to work with.
my_runs_df <- compile_activities(my_runs) %>%
filter (type == "Run", manual==FALSE)
desired_columns <- c('distance', 'average_speed', 'moving_time', 'start_date', 'start_date_local', 'map.summary_polyline', 'id', 'start_latitude', 'start_longitude', 'total_elevation_gain')
my_runs_df <- select(my_runs_df, match(desired_columns, names(my_runs_df)))
my_runs_df <- mutate(my_runs_df,
activity_no = seq(1,n(), 1),
moving_time = moving_time/60/60,
date = gsub("T.*$", '', start_date) %>%
as.POSIXct(., format = '%Y-%m-%d'),
month = format(date, "%m"),
day = format(date, "%d"),
year = format(date, "%Y")) %>%
mutate_at(., c('month', 'day'), as.numeric)
lons.range <- c(-71.25, -71.1)
lats.range <- c(42.33, 42.44)
view(my_runs_df)
Strava gives you spatial data in an encoded polyline. You can do a lot with this if you’re willing to get an API key from Google but it will require credit card information. The workaround is to use the Google Polylines package in R to decode the data, which I learned about from here. I mapped one run as a test.
run_one <- decode(my_runs_df$map.summary_polyline[1])
run_one_df <- data.frame(run_one)
leaflet(run_one_df) %>%
addProviderTiles(providers$Stamen.TonerLite) %>%
addPolylines(lng = ~ lon, lat = ~ lat)
Once I figured out how to work with the encoded polylines, I wrote a function that would decode each polyline in the dataframe called my_runs_df. Map.summary_polyline is the column where the spatial data is located.
run_list = purrr::map(my_runs_df$map.summary_polyline, function(x) decode(x))
Full credit for this problem solving goes to my partner John Russell, resident Python wizard, and also this stack overflow
all_runs <- leaflet() %>%
addProviderTiles(providers$Stamen.TonerLite) %>%
setView(lng=-71.122859,lat=42.397434,zoom=11) %>%
addControl("Running Routes in Somerville and Beyond", position = "topright")
for(i in 1:length(run_list)){
all_runs <- all_runs %>% addPolylines(data = data.frame(run_list[i]),
lng = ~ lon,
lat= ~ lat,
#label=i,
weight=0.6)
}
all_runs
saveWidget(all_runs, file = "allruns.html")
I manually selected seven routes that I would map in more detail. I assigned each of them a name and created labels that would show total distance and elevation gain.
fave_run_nums <- c(52, 185, 193, 81, 110,74, 210)
fave_run_names <- c("Full Minuteman", "Mystic Lakes Loop", "Fresh Pond Loop", "Tufts Track", "Home from the office", "Long Charles Loop", "Alewife Loop")
fave_runs <- leaflet() %>%
addProviderTiles(providers$Stamen.TonerLite) %>%
setView(lng=-71.122859,lat=42.397434,zoom=11) %>%
addControl("My Favorite Routes", position = "topright")
for(i in 1:length(fave_run_nums)){
describe <- paste(fave_run_names[i], "<br>", prettyNum(my_runs_df$distance[fave_run_nums[i]], digits = 3), " kilometers", "<br>",
prettyNum(my_runs_df$total_elevation_gain[fave_run_nums[i]], digits = 3), "meters elevation") %>%
lapply(htmltools::HTML)
fave_runs <- fave_runs %>% addPolylines(data = data.frame(run_list[fave_run_nums[i]]),
lng = ~ lon,
lat= ~ lat,
popup=describe,
weight=2,
highlightOptions = highlightOptions(color = "orange", weight = 6))
}
fave_runs
saveWidget(fave_runs, file = "faveruns.html")
After Monday’s class, I wanted to see if I could add a layer that would allow me to toggle on/off my favorite routes.
combined_runs <- leaflet() %>%
addProviderTiles(providers$Stamen.TonerLite) %>%
setView(lng=-71.122859,lat=42.397434,zoom=11) %>%
addControl("Running Routes in Somerville and Beyond", position = "topright")
for(i in 1:length(run_list)){
combined_runs <- combined_runs %>% addPolylines(data = data.frame(run_list[i]),
lng = ~ lon,
lat= ~ lat,
#label=i,
weight=0.6,
color="blue")
} %>%
addLayersControl(overlayGroups = fave_run_nums, options = layersControlOptions(collapsed = FALSE))
for(i in 1:length(fave_run_nums)){
describe <- paste(fave_run_names[i], "<br>", prettyNum(my_runs_df$distance[fave_run_nums[i]], digits = 3), " kilometers", "<br>",
prettyNum(my_runs_df$total_elevation_gain[fave_run_nums[i]], digits = 3), "meters elevation") %>%
lapply(htmltools::HTML)
fave_runs <- fave_runs %>% addPolylines(data = data.frame(run_list[fave_run_nums[i]]),
lng = ~ lon,
lat= ~ lat,
popup=describe,
color="orange",
weight=2,
highlightOptions = highlightOptions(color = "red", weight = 6))
}
combined_runs